﻿using AdvVerifyGUI.Repositories;
using AdvVerifyModels.Entities;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AdvVerifyGUI.Job;

class JobResultWriter(JobResultContext ctx) : IDisposable
{
    int id;
    readonly Dictionary<(int, int), (int, int)> dict = [];

    public async Task Write(JobResult result)
    {
        await ctx.AddAsync(result).ConfigureAwait(false);
        await ctx.SaveChangesAsync().ConfigureAwait(false);
        ctx.ChangeTracker.Clear();

        id = result.Id;
        foreach (var param in result.Paramaters)
        {
            foreach (var m in param.Measurements)
            {
                var p = param.PatternCopy.Pattern;
                dict[(m.ScanIndex, param.Index)] = (m.Id, p.CDPoints.Count);
            }
        }
    }

    public async Task WriteImage(string fn, ImageKind kind, int scanIndex)
    {
        ctx.Images.Add(new PatternImage
        {
            Kind = kind,
            ScanIndex = scanIndex,
            Filename = fn,
            JobResultId = id,
        });
        await ctx.SaveChangesAsync().ConfigureAwait(false);
    }

    public async Task WriteResult(string fn, double v, int scanIndex, int index)
    {
        var (mId, _) = dict[(scanIndex, index)];
        await ctx.Measurements
            .Where(m => m.Id == mId)
            .ExecuteUpdateAsync(setters => setters
                .SetProperty(r => r.Value, v)
                .SetProperty(r => r.Status, MeasurementStatus.Finished))
            .ConfigureAwait(false);
        ctx.Images.Add(new PatternImage
        {
            Kind = ImageKind.MP,
            ScanIndex = scanIndex,
            Index = index,
            Filename = fn,
            JobResultId = id,
        });
        await ctx.SaveChangesAsync().ConfigureAwait(false);
    }

    public async Task WriteRaw(string fn, int scanIndex, int index)
    {
        if (index == 0)
        {
            var (mId, n) = dict[(scanIndex, 0)];
            if (n == 0)
            {
                await ctx.Measurements
                    .Where(m => m.Id == mId)
                    .ExecuteUpdateAsync(setters => setters
                        .SetProperty(r => r.Status, MeasurementStatus.Finished))
                    .ConfigureAwait(false);
            }
        }

        ctx.Images.Add(new PatternImage
        {
            Kind = ImageKind.Raw,
            ScanIndex = scanIndex,
            Index = index,
            Filename = fn,
            JobResultId = id,
        });
        await ctx.SaveChangesAsync().ConfigureAwait(false);
    }

    public async Task WriteFailure(int scanIndex)
    {
        var i = 0;
        for (; ; )
        {
            if (!dict.TryGetValue((scanIndex, i), out var v))
            {
                break;
            }

            var (mId, _) = v;
            await ctx.Measurements
                .Where(m => m.Id == mId)
                .ExecuteUpdateAsync(setters => setters
                    .SetProperty(r => r.Status, MeasurementStatus.Failed))
                .ConfigureAwait(false);

            i += 1;
        }
    }

    public async Task WriteEndDate(DateTimeOffset time)
    {
        if (id == 0)
        {
            return;
        }

        await ctx.JobResults
                .Where(job => job.Id == id)
                .ExecuteUpdateAsync(setters => setters
                    .SetProperty(r => r.End, time.ToUnixTimeMilliseconds()))
                .ConfigureAwait(false);
        await ctx.SaveChangesAsync().ConfigureAwait(false);
    }

    public void Dispose()
    {
        ctx.Dispose();
    }
}